#ifndef FEATURE_ANALYZER_H
#define FEATURE_ANALYZER_H

#include "config.h"
#include "types.h"
#include "statistics.h"

#include "BPatch.h"
#include "BPatch_image.h"
#include "BPatch_basicBlock.h"
#include "BPatch_basicBlockLoop.h"

#include "Symtab.h"
#include "CFG.h"
#include "CodeObject.h"

#include <set>
#include <string>
#include <map>
#include <vector>
#include <unordered_map>

#define dprintf if (config->debug) printf

class FeatureAnalyzer {

    Config* config;
        
    // Internal functions are not written by authors
    // but produced by compilers.
    std::set<std::string> internalFuncs;
    void RecordAllInternalFunction(BPatch_image* image, Dyninst::ParseAPI::CodeObject *co);

    void ProduceIdiomFeature(Dyninst::ParseAPI::Function* f, Dyninst::ParseAPI::Block* b);
    void ProduceLoopIdiomFeature(const char *id, Dyninst::ParseAPI::Function *f, BPatch_basicBlockLoop *loop);

    void ProduceGraphletFeature(Dyninst::ParseAPI::Block *b);
    void ProduceLoopGraphletFeature(const char* id, Dyninst::ParseAPI::Function* f, BPatch_basicBlockLoop *loop);

    void ProduceLibcallFeature(Dyninst::ParseAPI::CodeObject *co, Dyninst::ParseAPI::Function* f, int label);

    void NGram(Dyninst::ParseAPI::SymtabCodeSource *sts, Dyninst::ParseAPI::Block *b, std::unordered_map<std::string,int> &counts);
    void ProduceNGramFeature(Dyninst::ParseAPI::SymtabCodeSource* sts, Dyninst::ParseAPI::Block *b);
    void ProduceLoopNGramFeature(const char *id, Dyninst::ParseAPI::SymtabCodeSource* sts, BPatch_basicBlockLoop *loop);

    void ProduceDataFeature(Dyninst::ParseAPI::Function *f, Dyninst::SymtabAPI::Symtab * obj, int label);

    int AddressingMode(Dyninst::ParseAPI::Block *b);
    void ProduceAddressingModeFeature(Dyninst::ParseAPI::Block *b);
    void ProduceLoopAddressingModeFeature(const char* id, BPatch_basicBlockLoop *loop);

    int AnalyzeALoop(const char* id, Dyninst::ParseAPI::SymtabCodeSource *sts, Dyninst::ParseAPI::Function *f, BPatch_basicBlockLoop *loop);

public:
    int totalFeatures;
    std::map<std::string, std::pair<int, std::string> > featureIndex;

    static bool NORT;
    static bool NOPLT;
    static int NODES;
    static int N;
    static bool ANON;
    static int MERGE;

    static BPatch bpatch;

    Statistics totalStat;
   
    FeatureAnalyzer(Config *c);
    int Analyze(char *fullpath);
    void PrintFeatureList();
    void AddAFeature(FILE* f, const std::string &feature, const std::string &human_format, int value);

};


#endif
